﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace C4DevContest
{
    public enum GamePiece { Red, Black, None };

    public class Connect4Board : ICloneable
    {
        private GamePiece[,] board = new GamePiece[Columns, Rows];
        private GamePiece aPiece;

        private const int Rows = 6;
        private const int Columns = 7;


        public Connect4Board()
        {
            init();
            aPiece = GamePiece.Black;
        }


        private void init()
        {
            for (int i = 0; i < Columns; i++)
            {
                for (int j = 0; j < Rows; j++)
                {
                    board[i, j] = GamePiece.None;
                }
            }
        }

        /// <summary>
        /// Gets a Piece at a given column/row.
        /// </summary>
        /// <param name="Col">0 based index of column</param>
        /// <param name="Row">0 based index of row</param>
        /// <returns>GamePiece</returns>
        public GamePiece GetPiece(int Col, int Row)
        {
            if(Col >= Columns || Col < 0)
            {
                throw new IndexOutOfRangeException("Invalid Column.");
            }

            if(Row >= Rows || Col < 0)
            {
                throw new IndexOutOfRangeException("Invalid Row.");
            }

            return board[Col, Row];
        }


        /// <summary>
        /// Drop a game piece into a given column.
        /// </summary>
        /// <param name="Col">0 based index of the column.</param>
        public void Move(int Col)
        {
            if (Col >= Columns || Col < 0)
            {
                throw new IndexOutOfRangeException("Invalid Column.");
            }

            for (int i = 0; i < Rows; i++)
            {
                if (board[Col, i] == GamePiece.None)
                {
                    board[Col, i] = aPiece;

                    if(aPiece == GamePiece.Red)
                        aPiece = GamePiece.Black;
                    else
                        aPiece = GamePiece.Red;

                    return;
                }
            }

            throw new Exception("Invalid Move.");
        }


        public bool IsGameOver()
        {
            if (WeHaveAWinner() != GamePiece.None) return true;

            for (int i = 0; i < Columns; i++)
            {
                if(IsValidMove(i))
                    return false;
            }

            return false;
        }


        /// <summary>
        /// Checks to see if a Move is valid.
        /// </summary>
        /// <param name="Col">0 based index of the column.</param>
        /// <returns>boolean</returns>
        public bool IsValidMove(int Col)
        {
            if (Col >= Columns || Col < 0) return false;

            for (int i = 0; i < Rows; i++)
            {
                if (board[Col, i] == GamePiece.None) return true;
            }

            return false;
        }

        /// <summary>
        /// Determines if someone has won the game.
        /// </summary>
        /// <returns>GamePiece of the winner.  GamePiece.None if there is no winner.</returns>
        public GamePiece WeHaveAWinner()
        {
            for (int i = 0; i < Columns; i++)
            {
                for(int j = 0; j < Rows; j++)
                {
                    GamePiece CurrentPiece = GetPiece(i, j);

                    if (CurrentPiece == GamePiece.None) continue;

                    if (j >= 3 && i <= 3)
                    {
                        if (CurrentPiece == GetPiece(i + 1, j - 1) &&
                            CurrentPiece == GetPiece(i + 2, j - 2) &&
                            CurrentPiece == GetPiece(i + 3, j - 3))
                            return CurrentPiece;
                    }

                    if (i <= 3)
                    {
                        if (CurrentPiece == GetPiece(i + 1, j) &&
                            CurrentPiece == GetPiece(i + 2, j) &&
                            CurrentPiece == GetPiece(i + 3, j))
                            return CurrentPiece;
                    }

                    if (j <= 2 && i <= 3)
                    {
                        if (CurrentPiece == GetPiece(i + 1, j + 1) &&
                            CurrentPiece == GetPiece(i + 2, j + 2) &&
                            CurrentPiece == GetPiece(i + 3, j + 3))
                            return CurrentPiece;
                    }

                    if (j <= 2)
                    {
                        if (CurrentPiece == GetPiece(i, j + 1) &&
                            CurrentPiece == GetPiece(i, j + 2) &&
                            CurrentPiece == GetPiece(i, j + 3))
                            return CurrentPiece;
                    }
                }
            }

            return GamePiece.None;
        }

        /// <summary>
        /// Clones the current GameBoard.  Useful for trying out moves without 
        /// messing up the actual playing board.
        /// </summary>
        /// <returns>Cloned Connect4Board</returns>
        public object Clone()
        {
            Connect4Board mc = new Connect4Board();

            for (int i = 0; i < Columns; i++)
            {
                for (int j = 0; j < Rows; j++)
                {
                    mc.board[i, j] = board[i, j];
                }
            }

            return mc;
        }
    }
}
